#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <memory.h>
#include <string.h>
#include "console.h"
#include "socket_udp.h"
#include "uv.h"

static CONSOLE_CMD_NODE_S gsConsoleCmdList[CONSOLE_CMD_MAX];

static int gsnConsoleLoopRun = 1;

console_msg_declare(console);

CONSOLE_CMD_NODE_S *Console_CmdSearch(char *pCmd);

int Console_Loop(uv_work_t *handle)
{
	int nRet = 0;
	int nSock = -1;
	SOCKET_UDP_SECTION_S stSection;
	char abyCmdRetBuf[16 * 1024];
	int nLen = 0;
	CONSOLE_CMD_PARAM_S stCmdParam;
	CONSOLE_CMD_NODE_S *pCmdNode = NULL;

	nSock = SocketUdpCreateServer("127.0.0.1", CONSOLE_UDP_PORT);
	if (nSock < 0)
	{
		console_error("Console udp server error\n");
		return -1;
	}

	stSection.nSocket = nSock;

	while (gsnConsoleLoopRun)
	{
		memset(abyCmdRetBuf, 0, sizeof(abyCmdRetBuf));
		// recv cmd
		nRet = SocketUdpRecv(&stSection, (char *)&stCmdParam, sizeof(stCmdParam));
		if (nRet < 0)
		{
			console_error("console SocketUdpRecv() error\n");
			goto _error;
		}

		// exe cmd here
		console_msg(console, "cmd:%s, args num:%d\n", stCmdParam.abyCmd, stCmdParam.nArgsNum);
		int i;
		for (i = 0; i < stCmdParam.nArgsNum; i++)
		{
			console_msg(console, "args[%d]:%s\n", i, stCmdParam.abyArgs[i]);
		}
		pCmdNode = Console_CmdSearch(stCmdParam.abyCmd);
		if (pCmdNode)
		{
			sprintf(abyCmdRetBuf, "cmd ok!\n");
			pCmdNode->cb(&stCmdParam, abyCmdRetBuf);
		}
		else
		{
			sprintf(abyCmdRetBuf, "Tim CMD, can not found cmd:%s\n", stCmdParam.abyCmd);
		}
		pCmdNode->cb(&stCmdParam, abyCmdRetBuf);
		// send result back
		SocketUdpSend(&stSection, (char *)abyCmdRetBuf, strlen(abyCmdRetBuf));
	}

	return 0;

_error:
	SocketUdpDestroyServer(nSock);
	return -1;
}

int Console_CmdAdd(char *pCmd, CONSOLE_CMD_CB cb)
{
	int i;
	char link[128] = {0};

	if (pCmd == NULL)
	{
		console_error("cmd is null!\n");
		return -1;
	}

	if (strlen(pCmd) >= sizeof(gsConsoleCmdList[0].abyCmd))
	{
		console_error("cmd too long:%s\n", pCmd);
		return -1;
	}

	for (i = 0; i < CONSOLE_CMD_MAX; i++)
	{
		if (gsConsoleCmdList[i].nUsed == 0)
		{
			strcpy(gsConsoleCmdList[i].abyCmd, pCmd);
			gsConsoleCmdList[i].cb = cb;
			gsConsoleCmdList[i].nUsed = 1;
			sprintf(link, "/usr/bin/%s", pCmd);
			unlink(link);
			symlink("/home/Tim/console_cmd", link);
			console_msg(console, "console cmd add %s ok!\n", pCmd);
			return 0;
		}
	}

	console_error("cmd too more!\n");

	return -1;
}

int Console_CmdDel(char *pCmd)
{
}

CONSOLE_CMD_NODE_S *Console_CmdSearch(char *pCmd)
{
	int i;
	CONSOLE_CMD_NODE_S *pNode = NULL;

	if (pCmd == NULL)
	{
		console_error("invalid args\n");
		return NULL;
	}

	for (i = 0; i < CONSOLE_CMD_MAX; i++)
	{
		if (strcmp(pCmd, gsConsoleCmdList[i].abyCmd) == 0)
		{
			pNode = &gsConsoleCmdList[i];
			return pNode;
		}
	}

	console_error("can not found cmd:%s\n", pCmd);
	return NULL;
}

static int Console_CmdSysQuit(CONSOLE_CMD_PARAM_S *pParam, char *pAck)
{
	if (pParam == NULL || pAck == NULL)
	{
		return -1;
	}

	gsnConsoleLoopRun = 0;

	sprintf(pAck, "ok");

	return 0;
}

int Console_Init(void)
{
	memset(gsConsoleCmdList, 0, sizeof(CONSOLE_CMD_NODE_S) * CONSOLE_CMD_MAX);

	console_level(console, 0);

	Console_CmdAdd("t-quit", Console_CmdSysQuit);

	return 0;
}

int Console_DeInit(void)
{
}

#define CONSOLE_CMD_CLIENT

#ifdef CONSOLE_CMD_CLIENT

int main(int argc, char **args)
{
	CONSOLE_CMD_PARAM_S stParams;
	int i;
	SOCKET_UDP_SECTION_S stSection;
	char abyAck[1024];
	int nRet;

	printf("console cmd client\n");
	memset(&stParams, 0, sizeof(stParams));

	strcpy(stParams.abyCmd, args[0]);

	if (argc > 1)
	{
		for (i = 1; i < argc; i++)
		{
			strcpy(stParams.abyArgs[i - 1], args[i]);
		}
		stParams.nArgsNum = argc - 1;
	}
	strcpy(stParams.abyArgs[CONSOLE_CMD_ARGS_NUM - 1], ttyname(0));

	// send
	stSection.nSocket = socket(AF_INET, SOCK_DGRAM, 0);
	if (stSection.nSocket < 0)
	{
		console_error("get socket error\n");
		return -1;
	}
	strcpy(stSection.abyRemoteIp, "127.0.0.1");
	stSection.nRemotePort = CONSOLE_UDP_PORT;
	SocketUdpSend(&stSection, (char *)&stParams, sizeof(stParams));
	memset(abyAck, 0, sizeof(abyAck));
	nRet = SocketUdpRecv(&stSection, abyAck, sizeof(abyAck));

	printf("cmd ack:\n%s\n", abyAck);

	close(stSection.nSocket);
	return 0;
}

#endif
